<template>
  <div v-show="!showDetail">
    <div class="container">
      <div class="left-panel">
        <div class="top-title">选择变量</div>
        <div id="g1">
          <div v-for="item in paramsList" :key="item.dictId" class="list_item" :data-id="item.dictId"> {{
            item.dictName }} </div>
        </div>
      </div>
      <div class="flexible-panel">
        <div class="top-title">
          <div>{{ showType }}</div>
          <div class="close-icon" @click="emitter.emit('closeNewFincial')"></div>
        </div>
        <BP v-if="showType == 'BP神经网络回归'"></BP>
        <SVR v-if="showType == '支持向量机(SVR)回归'"></SVR>
        <XIANXING v-if="showType == '线性回归'"></XIANXING>
        <div class="var-des">
          选择变量Y （变量数=1）
        </div>
        <div class="drag-area">
          <div class="drag-box">
            <div class="list-item">
              <div>信用评级</div>
            </div>
          </div>
        </div>
        <div class="var-des">
          选择自变量x （变量数≥5）
        </div>
        <div class="drag-areax" id="g2">
          <div class="drag-box" v-if="xList.length == 0">
            <div class="yStyle">拖入自变量x</div>
          </div>
          <div class="drag-box" v-else>
            <div v-for="item in xList" class="list-item" :data-id="item.dictId">
              <div>{{ item.dictName }}</div>
              <div class="close-icon" @click="deleteItem(item)"></div>
            </div>
          </div>
        </div>
        <div class="condition" v-if="showType !== '线性回归'">
          <div class="paramsBottom">
            <span>数据洗牌：</span>
            <el-select v-model="params.ShuffleData">
              <el-option label="是" :value="true" />
              <el-option label="否" :value="false" />
            </el-select>
            <el-tooltip popper-class="box-item-draggle" effect="dark" content="将数据重新打乱顺序按照训练重新分割数据。"
              placement="top-start">
              <el-icon style="margin-left: 10px;">
                <QuestionFilled />
              </el-icon>
            </el-tooltip>
          </div>
          <div class="paramsBottom" style="margin-left:50px">
            <span style="width:100px">训练占比：</span>
            <el-input-number type="number" v-model="params.TrainingPercentage" :min="0.5" :max="0.8" :precision="1"
              :step="0.1"></el-input-number>
            <el-tooltip popper-class="box-item-draggle" effect="dark" content="样本量中参与模型训练的比例。" placement="top-start">
              <el-icon style="margin-left: 10px;">
                <QuestionFilled />
              </el-icon>
            </el-tooltip>
          </div>
          <div class="paramsBottom" style="margin-left:50px">
            <span>交叉验证：</span>
            <el-select v-model="params.CrossValidation">
              <el-option label="是" :value="true" />
              <el-option label="否" :value="false" />
            </el-select>
            <el-tooltip popper-class="box-item-draggle" effect="dark" content="k折交叉验证将数据集划分为k个大小相似的互斥子集，每次用k-1个子集
                                                                的并集作为训练集，剩下的那一个子集作测试集，进行k次训练和测试，
                                                                最后返回k个评估结果的均值。可以避免由于数据集划分不合理而导致的
                                                                在训练集上过拟合问题。" placement="top-start">
              <el-icon style="margin-left: 10px;">
                <QuestionFilled />
              </el-icon>
            </el-tooltip>
          </div>
        </div>
        <div style="margin-left: 20px;" class="detail" v-if="showType !== '线性回归'" @click="settingDialog = true">更多设置>
        </div>
        <div class="foot-buttom">
          <el-button @click="handleDateDefault('reset')"> 重置 </el-button>
          <el-button @click="saveParams" type="primary">开始分析</el-button>
        </div>
      </div>
    </div>
  </div>
  <div v-if="showDetail">
    <div style="width:100%;height:100%">
      <div class="result-header">
        {{ showType }}
      </div>
      <div class="analy-result-process-wrap">
        <div class="analy-result-process-header">分析流程</div>
      </div>
      <div class="analy-result-process-content">
        <div class="process-header">
          <el-icon class='database' :size="25">
            <Coin />
          </el-icon>
          <span style="line-height: 20px; font-weight: 700;">
            数据源
          </span>
        </div>
        <div class="process-body">
          <span class="body-1">上市公司财务数据</span>
        </div>
      </div>
      <div class="analy-result-process-content">
        <div class="process-header">
          <el-icon class='database' :size="25">
            <HelpFilled />
          </el-icon>
          <span style="line-height: 20px; font-weight: 700;">
            算法配置
          </span>
        </div>
        <div class="process-body">
          <p class="body-p">算法：{{ showType }}</p>
          <p class="body-p">变量：变量X：｛{{ xListStr }}｝;变量Y：{信用评级} </p>
        </div>
      </div>
      <div class="analy-result-process-content">
        <div class="process-header">
          <el-icon class='database' :size="25">
            <Tickets />
          </el-icon>
          <span style="line-height: 20px; font-weight: 700;">
            分析结果
          </span>
        </div>
        <div class="process-body">
          <p class="body-p" v-if="showType !== '线性回归'">{{ showType }}基于MSE、RMSE、MAE、MAPE、R²指标对模型进行评价，请看详细结论。</p>
          <p class="body-p" v-else>线性回归用于研究自变量与因变量之间的线性关系：F检验的显著性P值为0.000***，水平上呈现显著性，拒绝回归系数为0的原假设，因此模型基本满足要求。</p>
        </div>
      </div>
      <!-- 分析步骤 -->
      <div class="analy-step">
        <div class="analy-result-process-wrap">
          <div class="analy-result-process-header">分析步骤</div>
        </div>
        <div v-if="showType == 'BP神经网络回归'">
          <div class="step-text">
            1.通过训练集数据来建立bp神经网络分类模型。
          </div>
          <div class="step-text">
            2.将建立的bp神经网络分类模型应用到训练、测试数据，得到模型的分类评估结果。
          </div>
          <div class="step-text">
            3.由于bp神经网络分类具有随机性，每次运算的结果不一样，若保存本次训练模型，后续可以直接上传数据代入到本次训练模型进行计算分类。
          </div>
          <div class="step-text">
            4.注：bp神经网络分类模型无法像传统模型一样得到确定的方程，通常通过测试数据分类效果来对模型进行评价。
          </div>
        </div>
        <div v-if="showType == '支持向量机(SVR)回归'">
          <div class="step-text">
            1.通过训练集数据来建立支持向量机(SVR)回归模型。
          </div>
          <div class="step-text">
            2.将建立的支持向量机(SVR)回归模型应用到训练、测试数据，得到模型评估结果。
          </div>
          <div class="step-text">
            3.由于支持向量机(SVR)回归具有随机性，每次运算的结果不一样，若保存本次训练模型，后续可以直接上传数据代入到本次训练模型进行计算预测。
          </div>
          <div class="step-text">
            4.注：支持向量机回归无法像传统模型一样得到确定的方程，通常通过测试数据预测精度来对模型进行评价。
          </div>
        </div>
        <div v-if="showType == '线性回归'">
          <div class="step-text">
            1.通过分析F值，分析其是否可以显著地拒绝总体回归系数为0的原假设，若呈显著性，表明之间存在着线性关系，至于线性关系的强弱，需要进一步进行分析。 </div>
          <div class="step-text">
            2.通过R²值分析模型拟合情况，同时对VIF值进行分析，若模型呈现共线性（VIF大于10或者5，严格为10），建议使用岭回归或者逐步回归。
          </div>
          <div class="step-text">
            3.分析X的显著性；如果呈现出显著性，则用于探究X对Y的影响关系。 </div>
          <div class="step-text">
            4.结合回归系数B值，对比分析X对Y的影响程度。
          </div>
          <div class="step-text">
            5.确定得到模型公式（Tips：使用线性回归前可以通过统计类的方法例如正态性检验等方式对数据进行验证清洗，也可以采用数据处理中异常值处理等方法对数据进行清洗。）。
          </div>
        </div>
      </div>
      <div class="analy-step">
        <div class="analy-result-process-wrap">
          <div class="analy-result-process-header">详细结论</div>
        </div>
        <div v-if="showType == '线性回归'">
          <div class="result-table">
            <span class="sub-title-text">
              输出结果1：线性回归分析结果表
            </span>
            <table style="text-align: center;width:99%">
              <thead>
                <tr style="height:40px">
                  <td colspan="10">线性回归分析结果 n=100</td>
                </tr>
                <tr>
                  <td rowspan="2"></td>
                  <td colspan="2">非标准化系数</td>
                  <td>标准化系数</td>
                  <td rowspan="2">t</td>
                  <td rowspan="2">P</td>
                  <td rowspan="2">VIF </td>
                  <td rowspan="2" class="wide-cell">R²</td>
                  <td rowspan="2" class="wide-cell">调整R²</td>
                  <td rowspan="2" class="wide-cell">F</td>
                </tr>
                <tr>
                  <td>B</td>
                  <td>标准误</td>
                  <td>Beta</td>
                </tr>
              </thead>
              <tbody>
                <tr v-for="(item, index) in lineDetaliData.dataList">
                  <td>{{ item[0] }}</td>
                  <td>{{ item[1] }}</td>
                  <td>{{ item[2] }}</td>
                  <td>{{ item[3] }}</td>
                  <td>{{ item[4] }}</td>
                  <td>{{ item[5] }}</td>
                  <td>{{ item[6] }}</td>
                  <td v-if="index === 0" :rowspan="lineDetaliData.dataList.length">{{ lineDetaliData.r2 }}</td>
                  <td v-if="index === 0" :rowspan="lineDetaliData.dataList.length">{{ lineDetaliData.adjustr2 }}</td>
                  <td v-if="index === 0" :rowspan="lineDetaliData.dataList.length">{{ lineDetaliData.f }}</td>
                </tr>
              </tbody>
              <tr style="height:40px">
                <td colspan="10">因变量：信用评级</td>
              </tr>
            </table>
            <div style="text-align: left;border: none !important;color: #000;margin-top: 10px;}">
              注：***、**、*分别代表1%、5%、10%的显著性水平</div>
            <span class="sub-title-text" style="margin-top:20px">
              图表说明：
            </span>
            <div class="step-text">
              上表格展示了本次模型的分析结果，包括模型的标准化系数、t值、VIF值、R²、调整R²等，用于模型的检验，并分析模型的公式。

            </div>
            <div class="step-text">
              1. 线性回归模型要求总体回归系数不为0，即变量之间存在回归关系。根据F检验结果对模型进行检验。
            </div>
            <div class="step-text">
              2. R²代表曲线回归的拟合程度，越接近1效果越好。
            </div>
            <div class="step-text">
              3. VIF值代表多重共线性严重程度，用于检验模型是否呈现共线性，即解释变量间存在高度相关的关系（VIF应小于10或者5，严格为5）若VIF出现inf，则说明VIF值无穷大，建议检查共线性，或者使用岭回归。
            </div>
            <div class="step-text">
              4. B是有常数情况下的的系数。
            </div>
            <div class="step-text">
              5. 标准误=B/t值。
            </div>
            <div class="step-text">
              6. 标准化系数是将数据标准化后得到的系数。
            </div>
            <div class="step-text">
              7. VIF是共线性。
            </div>
            <div class="step-text">
              8. F(df1,df2)是df1等于自变量数量；df2等于样本量-(自变量数量+1)。
            </div>
            <div class="step-text">
              9. F检验是为了判断是否存在显著的线性关系，R²是为了判断回归直线与此线性模型拟合的优劣。在线性回归中主要关注F检验是否通过，而在某些情况下R²大小和模型解释度没有必然关系。
            </div>

            <span class="sub-title-text" style="margin-top:20px">
              智能分析：
            </span>
            <div class="step-text">
              模型的公式如下：y=11.52 + 0.002*肺活量 - 0.006*负荷时间 - 0.105*吃零食情况 + 0.416*地区_城市 。”系数为B值，自变量X为新建模型时所选的变量名称。
            </div>
          </div>
        </div>
        <div v-else>
          <div class="result-table">
            <span class="sub-title-text">
              输出结果1：模型评估结果
            </span>
            <table style="text-align: center;width:95%">
              <tr>
                <th></th>
                <th>MSE</th>
                <th>RMSE</th>
                <th>MAE</th>
                <th>MAPE</th>
                <th>R²</th>
              </tr>
              <tbody>
                <tr>
                  <td>训练集</td>
                  <td>{{ bpSvrDetailData.mse }}</td>
                  <td>{{ bpSvrDetailData.rmse }}</td>
                  <td>{{ bpSvrDetailData.mae }}</td>
                  <td>{{ bpSvrDetailData.mape }}</td>
                  <td>{{ bpSvrDetailData.r2 }}</td>
                </tr>
                <!-- <tr>
                  <td>测试集</td>
                  <td>{{ bpSvrDetailData.mse_test }}</td>
                  <td>{{ bpSvrDetailData.rmse_test }}</td>
                  <td>{{ bpSvrDetailData.mae_test }}</td>
                  <td>{{ bpSvrDetailData.mape_test }}</td>
                  <td>{{ bpSvrDetailData.r2_test }}</td>
                </tr> -->
              </tbody>
            </table>
          </div>
          <div class="step-text">
            上表中展示了交叉验证集、训练集和测试集的预测评价指标，通过量化指标来衡量bp神经网络回归的预测效果。其中，通过交叉验证集的评价指标可以不断调整超参数，以得到可靠稳定的模型。
          </div>
          <div class="step-text">
            ● MSE（均方误差）： 预测值与实际值之差平方的期望值。取值越小，模型准确度越高。
          </div>
          <div class="step-text">
            ● RMSE（均方根误差）：为MSE的平方根，取值越小，模型准确度越高。
          </div>
          <div class="step-text">
            ● MAE（平均绝对误差）： 绝对误差的平均值，能反映预测值误差的实际情况。取值越小，模型准确度越高。
          </div>
          <div class="step-text">
            ● MAPE（平均绝对百分比误差）： 是 MAE 的变形，它是一个百分比值。取值越小，模型准确度越高。
          </div>
          <div class="step-text">
            ● R²： 将预测值跟只使用均值的情况下相比，结果越靠近 1 模型准确度越高。
          </div>
          <div class="result-table">
            <span class="sub-title-text">
              输出结果2：预测结果
              <el-select v-model="tableChange" @change="hanldeChangeTable" style="margin-left: 58%;">
                <el-option label="测试集" :value="1" />
                <el-option label="训练集" :value="2" />
              </el-select>
            </span>
            <table style="text-align: center; margin-bottom: 20px; width:95%" id="myTable" v-show="tableChange == 1">
              <thead>
                <tr>
                  <th>预测测试集结果Y</th>
                  <th v-for="item in bpSvrDetailData.bpSvrDetailHeader">{{ item }}</th>
                </tr>
              </thead>
            </table>
            <table style="text-align: center; margin-bottom: 20px; width:99%;" id="myTable1" v-if="tableChange == 2">
              <thead>
                <tr>
                  <th>预测结果集结果Y</th>
                  <th v-for="item in bpSvrDetailData.bpSvrDetailHeader">{{ item }}</th>
                </tr>
              </thead>
            </table>
          </div>
        </div>
      </div>

      <div class="foot-buttom">
        <div v-if="!!detailData">
          <el-button @click="emitter.emit('closeNewFincial')"> 关闭 </el-button>
        </div>
        <div v-else>
          <el-button @click="backToNew"> 返回 </el-button>
          <el-button @click="confirmVisible = true" type="primary">保存</el-button>
        </div>
      </div>
    </div>
  </div>
  <!-- 确认提交弹窗 -->
  <ReDialog :width="600" :height="200" :models="confirmVisible" @Closes="confirmVisible = false">
    <template #header>
      <h2 style=" text-align: center;">确认保存模型</h2>
    </template>
    <template #main>
      <div style="display:flex;justify-content: center;">
        <h3>请输入模型名称:</h3> <el-input v-model.trim="params.modelName" style="width:200px;margin-left:20px"></el-input>
      </div>
    </template>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="saveSSS()" type="primary">确定</el-button>
        <el-button @click="confirmVisible = false"> 取消 </el-button>
      </span>
    </template>
  </ReDialog>
  <!-- 算法参数设置 -->
  <el-dialog v-model="settingDialog" :close-on-click-modal="false" width="50%">
    <template #header>
      <h2 style="text-align: center;">模型参数设置</h2>
    </template>
    <el-scrollbar height="500px">
      <div v-if="showType == 'BP神经网络回归'" style="  margin-top: 15px;margin-left: 20px;">
        <div class="setting-item">
          <span>激活函数</span>
          <el-select style="margin-left: 85px;" v-model="params.ActivationFunction">
            <el-option label="identity" :value="'identity'" />
            <el-option label="logistic" :value="'logistic'" />
            <el-option label="tanh" :value="'tanh'" />
            <el-option label="relu" :value="'relu'" />
          </el-select>
          <el-tooltip popper-class="box-item-draggle" effect="dark" placement="top-start">
            <template #content>引入激活函数是为了增加神经网络模型的非线性能力。<br />● identity 适合于潜在行为是线性（与线性回归相似）的任务。<br />● logistic
              函数在用于分类器时，效果更好。<br />● tanh 函数解决了 logistic 中心不为 0 的缺点，但依旧有梯度易消失的缺点。<br />● tanh 函数解决了 logistic 中心不为 0
              的缺点，但依旧有梯度易消失的缺点。</template>
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>求解器</span>
          <el-select style="margin-left: 100px;" v-model="params.Solver">
            <el-option label="lbfgs" :value="'lbfgs'" />
            <el-option label="sgd" :value="'sgd'" />
            <el-option label="adam" :value="'adam'" />
          </el-select>
          <el-tooltip popper-class="box-item-draggle" effect="dark" placement="top-start">
            <template #content>求解器的目标是希望找到一组模型参数，使模型在所有训练数据上的平均损失最小。<br />● sgd
              ：在梯度下降法基础上，sgd对单个训练样本进行参数更新，加快收敛速率。<br />●
              adam： 在梯度下降法基础上，通过计算梯度的一阶矩估计和二阶矩估计而为不同的参数设计独立的自适应性学习率，加快收敛速率。
              <br />● lbfgs：sgd、Adam等都是在一阶法（梯度下降法）的基础上进行改进，加快收敛速率。
              而lbfgs在二阶泰勒展开式进行局部近似平均损失的基础上进行改进的，以降低了迭代过程中的存储量，加快收敛速率。</template>
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>学习率</span>
          <el-input-number type="number" v-model="params.LearningRate" :min="0.0001" :max="1" :precision="4"
            style="margin-left: 100px;" :step="0.0001"></el-input-number>
          <el-tooltip popper-class="box-item-draggle" effect="dark" placement="top-start">
            <template #content>合适的学习率能够使目标函数在合适的时间内收敛到局部最小值。<br />● 学习率设置太小，结果收敛非常缓慢。
              <br />● 学习率设置太大，结果在最优值附近徘徊，难以收敛。
            </template>
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>L2正则化项</span>
          <el-input-number type="number" v-model="params.L2Regularization" :min="0.0" :precision="1"
            style="margin-left: 70px;" :step="0.5"></el-input-number>
          <el-tooltip style="width: 400px !important;" effect="dark" content="L2范数容易得到平滑解,可以用来考虑降低过拟合。增加此值将增大惩罚，使模型更加保守。"
            placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>迭代次数</span>
          <el-input-number type="number" v-model="params.Iterations" :min="1" :max="100"
            style="margin-left: 85px;"></el-input-number>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="神经网络通过反向传播误差逐步更新权值，达到误差逐步收敛的目的。
                                                                （每一次反向传播误差更新权值，都是一次迭代过程。）" placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div style="color:rgb(170, 173, 177);font-size: 14px;margin-bottom: 10px; margin-top:20px" class="setting-item">
          隐藏层神经元数量 <el-tooltip popper-class="box-item-draggle" effect="dark" placement="top-start">
            <template #content>隐藏层的意义就是把输入数据的特征，抽象到另一个维度空间，来展现其更抽象化的特征。<br />● 一般来说，一或两层的隐藏层已经能够解决很多问题了，如果数据量多，可以在防止出
              现过拟合的情况下适当的增加层数。
              <br />● 而隐藏层数量也要适当，一般来说，隐藏层的节点数必须小于n-1，其中n是训练样本数量
            </template>
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip></div>
        <div style="  margin-top: 15px;">
          <div class="setting-item" v-for="(item, index) in HiddenLayerNeuronsList">
            <span>隐藏层{{ index + 1 }}:</span>
            <el-input-number type="number" v-model="item.layerNeuron" :min="1"
              style="margin-left: 70px;"></el-input-number>
            <el-button size="small" :icon="Plus" circle style="margin-left:10px" @click="addHiddenLayerNeurons()" />
            <el-button size="small" :icon="Minus" circle @click="addDelete(index)" />
          </div>
        </div>
      </div>
      <div v-if="showType == '支持向量机(SVR)回归'" style=" margin-top: 15px;margin-left: 20px;">
        <div class="setting-item">
          <span>惩罚系数</span>
          <el-input-number type="number" v-model="params.PenaltyCoefficient" :min="0.01" :precision="2"
            style="margin-left:85px;" :step="0.01"></el-input-number>
          <el-tooltip style="width: 400px !important;" effect="dark" content="惩罚系数值越高，说明越不能容忍出现误差。" placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>核函数</span>
          <el-select style="margin-left: 100px;" v-model="params.KernelFunction">
            <el-option label="rbf核函数" :value="'rbf'" />
            <el-option label="linear核" :value="'linear'" />
            <el-option label="poly核函数" :value="'poly'" />
            <el-option label="sigmoid核函数" :value="'sigmoid'" />
          </el-select>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="惩罚系数值越高，说明越不能容忍出现误差。" placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>核函数最高项次数</span>
          <el-input-number type="number" v-model="params.DegreeOfPolynomialKernel" :min="1"
            style="margin-left: 30px;"></el-input-number>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="核函数的最高项次数越大，复杂度越大，容易过拟合。"
            placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>核函数系数</span>
          <el-select style="margin-left: 71px;" v-model="params.CoefficientOfKernel">
            <el-option label="scale" :value="'scale'" />
            <el-option label="auto" :value="'auto'" />
            <el-option label="自定义" :value="'custom'" />
          </el-select>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="如果是scale，则为特征数*方差的倒数。
                                                                如果是auto，则为特征数的倒数。" placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
          <el-input-number type="number" v-model="params.CoefficientOfKernelValue" :min="0.01" :max="0.47" :precision="2"
            style="margin-left:71px;" :step="0.01" v-if="params.CoefficientOfKernel == 'custom'"></el-input-number>
        </div>
        <div class="setting-item">
          <span>核函数常数</span>
          <el-input-number type="number" v-model="params.KernelFunctionConstant" :precision="1" :step="0.1"
            style="margin-left: 71px;"></el-input-number>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="增大核函数常数会增加复杂度，增加拟合能力，容易造成过拟合。"
            placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>误差收敛条件</span>
          <el-input-number type="number" v-model="params.ToleranceForConvergence" :min="0.000" :precision="3"
            style="margin-left: 60px;" :step="0.001"></el-input-number>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="停止训练的误差值大小。" placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
        <div class="setting-item">
          <span>最大迭代次数</span>
          <el-input-number type="number" v-model="params.MaximumIterations" :min="100" :max="1000"
            style="margin-left: 60px;"></el-input-number>
          <el-tooltip popper-class="box-item-draggle" effect="dark" content="若算法不能收敛，则当达到最大迭代次数时就停止计算。"
            placement="top-start">
            <el-icon style="margin-left: 10px;">
              <QuestionFilled />
            </el-icon>
          </el-tooltip>
        </div>
      </div>
    </el-scrollbar>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="addSetting" type="primary">确定</el-button>
        <el-button @click="settingDialog = false"> 取消 </el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup lang='ts'>
import { ref, watch, reactive, nextTick, onMounted } from 'vue';
import {
  SaveBSSpneuralnetworkalgorithmResult
} from "@/api/stu/SupplyChainFinance";
import { emitter } from "@/utils/mitt";
import Sortable from 'sortablejs'
import BP from './BP.vue'
import SVR from './SVR.vue'
import XIANXING from './XianXing.vue'
import { useRoute } from "vue-router";
import {
  AlgorithmCreate,
} from "@/api/stu/SupplyChainFinance";
import {
  Plus,
  Minus,
  QuestionFilled,
  Coin,
  HelpFilled,
  Tickets
} from "@element-plus/icons-vue";
import { ElMessage } from 'element-plus';
const props = defineProps({
  showType: {
    type: String,
    required: true
  },
  //算法类型
  data: {
    type: Object,
    required: true
  },
  //算法参数对象
  showId: {
    type: String,
    required: true
  },
  detailData: {
    type: Object,
    required: true
  },
  //算法id
});
const taskTittleRegex = /^[\u4e00-\u9fffa-zA-Z0-9]{1,30}$/
const route = useRoute()
const xList = ref([])
const xListStr = ref()
const paramsList = ref([])
const acrmId = ref() //用于保存的数据id
const params: {
  ShuffleData: boolean;
  TrainingPercentage: number;
  CrossValidation: boolean;
  ActivationFunction: string;
  Solver: string;
  LearningRate: number;
  L2Regularization: number;
  Iterations: number;
  PenaltyCoefficient?: number;
  KernelFunction?: string;
  CoefficientOfKernel?: string;
  KernelFunctionConstant?: number;
  DegreeOfPolynomialKernel?: number;
  CoefficientOfKernelValue?: number;
  ToleranceForConvergence?: number;
  MaximumIterations?: number;
  modelName?: string;
} = reactive({});
//控制新建完查看报告
const showDetail = ref(false)
const confirmVisible = ref(false)
//bp和svr详情数据（列表查看以及生成报告）
const bpSvrDetailData = reactive({
  mse: 0,
  rmse: 1,
  mae: 2,
  mape: 3,
  r2: 4,
  mse_test: 5,
  rmse_test: 6,
  mae_test: 7,
  mape_test: 8,
  r2_test: 9,
  bpSvrDetailHeader: [],
  y_pred_train: [], //预测训练集数据
  y_pred_test: [],//预测测试集数据
})
const lineDetaliData = reactive({
  xListStr: [],
  dataList: [],
  r2: '',
  adjustr2: '',
  f: ''
})
const tableChange = ref(1)
const HiddenLayerNeuronsList = ref([{ layerNeuron: 100 }])
const settingDialog = ref(false)
function handleDraggle(arr) {
  paramsList.value = props.data.filter((d) => arr.includes(d.dictId) && d.dictName !== "信用评级");
  xList.value = props.data.filter((d) => !arr.includes(d.dictId) && d.dictName !== "信用评级");
}

onMounted(() => {
  //如果是详情直接跳到查看结果
  if (!!props.detailData) {
    handleJumpDetail()
  } else {
    paramsList.value = props.data.filter(item => item.dictName !== '信用评级')
    nextTick(() => {
      var g1 = document.getElementById('g1');
      var ops1 = {
        animation: 200,
        draggable: ".list_item",
        sort: false,
        group: { name: "itxst", pull: true, put: true },
        //拖动结束
        onEnd: function (evt) {
          var arr = sortable1.toArray();
          handleDraggle(arr)
        },
      };
      var sortable1 = Sortable.create(g1, ops1);
      //第二组
      var g2 = document.getElementById('g2');
      var ops2 = {
        animation: 200,
        draggable: ".list-item",
        sort: false,
        group: { name: "itxst", pull: true, put: true },
        //拖动结束
      };
      var sortable2 = Sortable.create(g2, ops2);
      //第三组
    })
    //处理预设数据
    handleDateDefault()
  }
})
function handleJumpDetail() {
  showDetail.value = true
  if (props.detailData.bpSvrDetailHeader) {
    xListStr.value = props.detailData.bpSvrDetailHeader.join(',')
    nextTick(() => {
      bpSvrDetailData.bpSvrDetailHeader = props.detailData.bpSvrDetailHeader
      bpSvrDetailData.mse = props.detailData.mse
      bpSvrDetailData.rmse = props.detailData.rmse
      bpSvrDetailData.mae = props.detailData.mae
      bpSvrDetailData.mape = props.detailData.mape
      bpSvrDetailData.r2 = props.detailData.r2
      bpSvrDetailData.mse_test = props.detailData.mse_test
      bpSvrDetailData.rmse_test = props.detailData.rmse_test
      bpSvrDetailData.mae_test = props.detailData.mae_test
      bpSvrDetailData.mape_test = props.detailData.mape_test
      bpSvrDetailData.r2_test = props.detailData.r2_test
      bpSvrDetailData.y_pred_test = props.detailData.y_pred_test;
      bpSvrDetailData.y_pred_train = props.detailData.y_pred_train;
      //生成Table
      var table = document.getElementById("myTable");
      for (var i = 0; i < bpSvrDetailData.y_pred_test.length; i++) {
        var row = table.insertRow(i + 1);
        for (var j = 0; j < bpSvrDetailData.y_pred_test[i].length; j++) {
          var cell = row.insertCell(j);
          cell.innerHTML = bpSvrDetailData.y_pred_test[i][j];
          console.log(cell)
          cell.style.border = '1px solid #bab9b9';
        }
      }
    })
  } else {
    props.showType = '线性回归'
    xListStr.value = props.detailData.xListStr.join(',')
    lineDetaliData.dataList = props.detailData.dataList
    lineDetaliData.r2 = props.detailData.r2
    lineDetaliData.adjustr2 = props.detailData.adjustr2
    lineDetaliData.f = props.detailData.f
  }
}
// 处理预设数据
function handleDateDefault(reset) {
  params.modelName = ''
  if (props.showType == 'BP神经网络回归') {
    params.ShuffleData = false;
    params.TrainingPercentage = 0.5;
    params.CrossValidation = false;
    params.ActivationFunction = 'logistic'
    params.Solver = 'lbfgs'
    params.LearningRate = 1.0000
    params.L2Regularization = 0.0;
    params.Iterations = 1
    HiddenLayerNeuronsList.value = [{ layerNeuron: 100 }]
  } else if (props.showType == '支持向量机(SVR)回归') {
    params.ShuffleData = false;
    params.TrainingPercentage = 0.7;
    params.CrossValidation = false;
    params.PenaltyCoefficient = 1.00
    params.KernelFunction = 'poly'
    params.CoefficientOfKernel = "custom",
      params.CoefficientOfKernelValue = 0.4
    params.DegreeOfPolynomialKernel = 2,
      params.KernelFunctionConstant = 0.5
    params.ToleranceForConvergence = 0.002
    params.MaximumIterations = 100
  } else {
    params.ShuffleData = false;
    params.TrainingPercentage = 0.7;
    params.CrossValidation = false;
  }
  if (reset) {
    paramsList.value = props.data.filter(item => item.dictName !== '信用评级')
    xList.value = []
    ElMessage.success('重置数据成功')
  }
}
function deleteItem(item) {
  let removedData = {}
  for (let i = 0; i < xList.value.length; i++) {
    if (xList.value[i].dictId == item.dictId) {
      // 从 group1 中删除数据
      removedData = xList.value.splice(i, 1)[0];
      break;
    }
  }
  // 将删除的数据移动到 group2
  paramsList.value.push(removedData);
}
//隐藏层参数操作
function addHiddenLayerNeurons() {
  if (HiddenLayerNeuronsList.value.length == 5) {
    ElMessage.warning('最多存在五个隐藏层')
    return
  }
  HiddenLayerNeuronsList.value.push({ layerNeuron: 100 })
}

function addDelete(index) {
  if (HiddenLayerNeuronsList.value.length == 1) {
    ElMessage.warning('最少保留一个隐藏层')
    return
  }
  HiddenLayerNeuronsList.value.splice(index, 1);
}

function addSetting() {
  settingDialog.value = false
  ElMessage.success('模型参数设置已保存')
}
async function saveParams() {
  if (xList.value.length < 5) {
    ElMessage.warning('请至少选择5个变量')
    return
  }
  const { showId, showType } = props;
  const data = {
    ModelType: 1,
    taskId: route.query.taskId,
    planId: route.query.planId,
    indexSelection: xList.value.map(item => item.dictValue).join(',') + ',CreditRating',
    algorithmTypeId: props.showId,
    type: showType == 'BP神经网络回归' ? 1 : showType == '支持向量机(SVR)回归' ? 2 : 3,
    algorithmAnalysisRequestDto: {
      ModelType: 1,
      isApprovedMeasurement: false,
      querySqlString: xList.value.map(item => item.dictValue).join(',') + ',CreditRating',
      columnName: xList.value.map(item => item.dictValue).join(';') + ';CreditRating',
      selectdy: "CreditRating",
      algorithmTypeEnum: showType == 'BP神经网络回归' ? 1 : showType == '支持向量机(SVR)回归' ? 2 : 3,
      algorithmParameters: showType == '支持向量机(SVR)回归' ? {
        trainingPercentage: params.TrainingPercentage,
        penaltyCoefficient: params.PenaltyCoefficient || 0,
        kernelFunction: params.KernelFunction || '',
        degreeOfPolynomialKernel: params.DegreeOfPolynomialKernel || 0,
        coefficientOfKernelValue: params.CoefficientOfKernelValue || '',
        coefficientOfKernel: params.CoefficientOfKernel || '',
        kernelFunctionConstant: params.KernelFunctionConstant || '',
        toleranceForConvergence: params.ToleranceForConvergence || 0,
        maximumIterations: params.MaximumIterations || 0,
      } : '',
      neuralNetworkParameters: showType == 'BP神经网络回归' ? {
        trainingPercentage: params.TrainingPercentage,
        activationFunction: params.ActivationFunction,
        solver: params.Solver,
        learningRate: params.LearningRate,
        l2Regularization: params.L2Regularization,
        iterations: params.Iterations,
        hiddenLayerNeurons: HiddenLayerNeuronsList.value.map(item => item.layerNeuron)
      } : '',
      xGBoostConfig: '',
      decisionTreeRegressionConfig: '',
      knnConfig: '',
      randomForestRegressionConfig: ''
    },
  };
  if (showType == 'BP神经网络回归') {
    data.ModelParameterSetting = JSON.stringify(data.algorithmAnalysisRequestDto.neuralNetworkParameters)
  }
  if (showType == '支持向量机(SVR)回归') {
    data.ModelParameterSetting = JSON.stringify(data.algorithmAnalysisRequestDto.algorithmParameters)
  }
  let res = await AlgorithmCreate(data)
  if (res.success) {
    handleNewReport(res.data)
  } else {
    ElMessage.error(res.msg)
  }
}

function handleNewReport(data) {
  showDetail.value = true
  xListStr.value = xList.value.map(item => item.dictName).join(',')
  if (props.showType !== '线性回归') {
    nextTick(() => {
      bpSvrDetailData.bpSvrDetailHeader = xList.value.map(item => item.dictName)
      const head = xList.value.map(item => item.dictValue)
      const result = []; //测试集
      const result1 = [];//训练集
      acrmId.value = data.acrmId
      bpSvrDetailData.mse = data.mse
      bpSvrDetailData.rmse = data.rmse
      bpSvrDetailData.mae = data.mae
      bpSvrDetailData.mape = data.mape
      bpSvrDetailData.r2 = data.r2
      bpSvrDetailData.mse_test = data.mse_test
      bpSvrDetailData.rmse_test = data.rmse_test
      bpSvrDetailData.mae_test = data.mae_test
      bpSvrDetailData.mape_test = data.mape_test
      bpSvrDetailData.r2_test = data.r2_test
      //处理测试集数据
      for (const obj of data.test_financial_data) {
        const item = [];
        for (const property of head) {
          item.push(obj[property]);
        }
        result.push(item);
      }
      for (let i = 0; i < result.length; i++) {
        console.log(data.y_pred_test[i]);

        result[i].unshift(data.y_pred_test[i]);
      }
      //处理训练集数据
      for (const obj of data.financial_data) {
        const item = [];
        for (const property of head) {
          item.push(obj[property]);
        }
        result1.push(item);
      }
      for (let i = 0; i < result1.length; i++) {
        result1[i].unshift(data.y_pred_train[i]);
      }
      bpSvrDetailData.y_pred_test = result;
      bpSvrDetailData.y_pred_train = result1;
      //生成Table
      var table = document.getElementById("myTable");
      console.log(result.length)
      for (var i = 0; i < result.length; i++) {
        var row = table.insertRow(i + 1);
        for (var j = 0; j < result[i].length; j++) {
          var cell = row.insertCell(j);
          cell.innerHTML = result[i][j];
          console.log(cell)
          cell.style.border = '1px solid #bab9b9';
        }
      }
    })
  } else {
    acrmId.value = data.acrmId
    //处理线性回归
    const head = xList.value.map(item => item.dictValue)
    xListStr.value = xList.value.map(item => item.dictName).join(',')
    const transformedData = head.map(item => [item])
      .map((item, index) => [...item, Object.values(data.b)[index]])
      .map((item, index) => [...item, data.standardError[item[0]]])
      .map((item, index) => [...item, Object.values(data.beta)[index]])
      .map((item, index) => [...item, data.t[item[0]]])
      .map((item, index) => [...item, data.p[item[0]]])
      .map((item, index) => [...item, Object.values(data.vif)[index]]);
    const resetHead = xList.value.map(item => item.dictName)
    transformedData.forEach((arr, index) => {
      arr[0] = resetHead[index];
    })
    lineDetaliData.xListStr = xList.value.map(item => item.dictName)
    lineDetaliData.dataList = transformedData;
    lineDetaliData.r2 = data.r2
    lineDetaliData.adjustr2 = data.adjustr2
    lineDetaliData.f = data.f
  }

}

function hanldeChangeTable() {
  if (tableChange.value == 1) {
    return
  } else {
    nextTick(() => {
      var table = document.getElementById("myTable1");
      console.log(bpSvrDetailData.y_pred_train.length)
      for (var i = 0; i < bpSvrDetailData.y_pred_train.length; i++) {
        var row = table.insertRow(i + 1);
        for (var j = 0; j < bpSvrDetailData.y_pred_train[i].length; j++) {
          var cell = row.insertCell(j);
          cell.innerHTML = bpSvrDetailData.y_pred_train[i][j];
          cell.style.border = '1px solid #bab9b9';
        }
      }
    })
  }
}

async function saveSSS() {
  if (params.modelName == '') {
    ElMessage.warning('请输入模型名称')
    return
  }
  if (taskTittleRegex.test(params.modelName) == false) {
    ElMessage.warning('模型名称不得输入特殊字符,不得重复，且长度为1-30个字符')
    return
  }
  const { showId, showType } = props;
  const data = {
    AlgorithmModelName: params.modelName,
    taskId: route.query.taskId,
    planId: route.query.planId,
    type: showType == 'BP神经网络回归' ? 1 : showType == '支持向量机(SVR)回归' ? 2 : 3,
    acrmId: acrmId.value,
    algorithmCalculateResult: showType == '线性回归' ? JSON.stringify(lineDetaliData) : JSON.stringify(bpSvrDetailData),
    modelType: 1,
    BpSvrDetailHeader: '信用评级,' + xList.value.map(item => item.dictName).join(',')
  }
  let res = await SaveBSSpneuralnetworkalgorithmResult(data)
  if (res.success) {
    confirmVisible.value = false
    showDetail.value = false
    emitter.emit('closeNewFincial')
    emitter.emit('refreshTable')
    ElMessage.success('新增信用评级模型成功！')
  } else {
    ElMessage.error(res.msg)
  }
}

function backToNew() {
  showDetail.value = false
  tableChange.value = 1
}
</script>
<style>
.box-item-draggle {
  max-width: 50%;
}
</style>
<style scoped lang="scss" >
.container {
  height: 100%;
  display: flex;
}

.left-panel {
  width: 200px;
  border-right: 1px solid #eef1f5;
  user-select: none;
}

.flexible-panel {
  flex-grow: 1;
  overflow-y: auto;
  overflow-x: hidden;
  flex: 1;
}

.list_item {
  padding: 0 12px 0 20px;
  font-size: 12px;
  cursor: move;
  color: #6a6f77;
  align-items: center;
  margin-bottom: 12px;
}

.top-title {
  padding: 10px 12px 10px 20px;
  margin-bottom: 15px;
  border-bottom: 1px solid #eef1f5;
  display: flex;
  justify-content: space-between
}

.var-des {
  padding: 18px 20px;
  font-size: 12px;
}

.drag-area {
  margin-left: 20px;
  border: 1px dashed #d8d8d8;
  overflow-y: auto;
  min-height: 40px;
  flex-basis: 40px;
  height: 40px;
  flex-grow: 0;
}

.drag-areax {
  margin-left: 20px;
  border: 1px dashed #d8d8d8;
  overflow-y: auto;
  min-height: 240px;
  flex-basis: 40px;
  height: 40px;
  flex-grow: 0;
}

.drag-box {
  width: 100%;
  height: 100%;
  position: relative;
}

.yStyle {
  height: 100%;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  color: #aaadb1;
  font-size: 14px;
  position: absolute;
  left: 0;
  top: 0;
}

.list-item {
  height: 30px;
  font-size: 12px;
  padding: 0 20px;
  align-items: center;
  cursor: move;
  justify-content: space-between;
  display: flex;
  user-select: none;
}

.close-icon {
  position: relative;
  display: inline-block;
  width: 20px;
  height: 20px;
  cursor: pointer;
}

.close-icon::before,
.close-icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 2px;
  height: 10px;
  background-color: red;
  transform: translate(-50%, -50%) rotate(45deg);
}

.close-icon::before {
  transform: translate(-50%, -50%) rotate(-45deg);
}

.condition {
  margin-top: 15px;
  margin-left: 20px;
  display: flex;
}

.paramsBottom {
  display: flex;
  align-items: center;
  font-size: 12px;
}

.detail {
  color: #1a78ff;
  cursor: pointer;
  font-size: 12px;
  display: inline-flex;
  flex-wrap: nowrap;
}

.setting-item {
  display: flex;
  align-items: center;
  margin-top: 10px;
}

.foot-buttom {
  display: flex;
  text-align: right;
  justify-content: center;
  margin-top: 50px;
}

.result-header {
  padding: 0px 30px px;
  height: 40px;
  width: 100%;
  line-height: 40px;
  font-family: PingFangSC, PingFangSC-Medium;
  text-align: left;
  color: #2b323d;
  border-bottom: 1px solid #eef1f5;
}

.analy-result-process-wrap {
  margin-top: 16px;
  margin-bottom: 20px;
  font-family: PingFangSC, PingFangSC-Medium;
}

.analy-result-process-header {
  color: rgb(43, 50, 61);
  height: 22px;
  margin-bottom: 16px;
  font-weight: 700;
  display: flex;
  font-size: 14px;
  align-items: center;
}

.analy-result-process-header::before {
  content: "";
  width: 4px;
  height: 16px;
  margin-right: 10px;
  background-color: rgb(26, 120, 255);
}

.analy-result-process-content {
  margin-left: 14px;
}

.process-header {
  display: flex;
  font-size: 14px;
  align-items: center;
  color: rgb(43, 50, 61);
  margin: 10px 0px 8px;
}

.database {
  color: rgb(26, 120, 255);
  margin-right: 8px
}

.process-body {
  margin-left: 14px;
  padding-left: 22px;
  border-left: 1px solid rgba(26, 120, 255, 0.3);
  min-height: 28px;
  line-height: 12px;
  position: relative;
  font-weight: 400;
  font-size: 12px;
}

.process-body::before {
  content: "";
  width: 0px;
  height: 0px;
  border-width: 4px;
  border-style: solid;
  border-image: initial;
  border-color: rgba(26, 120, 255, 0.5) transparent transparent;
  position: absolute;
  left: -4px;
  bottom: -8px;
  translate: -0.5px;
}

.body-1 {
  text-decoration: underline;
  color: rgb(26, 120, 255);
  line-height: 18px;
  cursor: pointer;
}

.body-p {
  color: rgb(106, 111, 119);
  line-height: 18px;
  margin-bottom: 4px;
  width: 100%;
}


table,
th,
td {
  border: 1px solid #bab9b9;
  border-collapse: collapse;
}

.analy-step {
  margin-bottom: 40px;
  margin-top: 16px;
  font-size: 14px;
}

.step-text {
  margin-left: 14px;
  font-family: PingFangSC, PingFangSC-Regular;
  font-weight: 400;
  color: #6a6f77;
  white-space: pre-wrap;
}

.result-table {
  margin-bottom: 20px;
  margin-left: 20px
}

.sub-title-text {
  font-family: PingFangSC, PingFangSC-Medium;
  font-weight: 700;
  color: #2b323d;
  height: 26px;
  display: flex;
  align-items: center;
  margin-bottom: 20px;
}

.wide-cell {
  width: 50px;
  /* 自定义宽度，可以根据需要进行调整 */
}
</style>
